RestTemplate使用說明

RestTemplate介绍

RestTemplate是Spring提供的用于访问Rest服务的客户端,同时RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。

RestTemplate初探

通过实例展示RestTemplate的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Test
public void test01(){
RestTemplate restTemplate = new RestTemplate();
String url = "http://www.baidu.com?id={id}&name={name}&num={age}";
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class, 1, "Elon", 20);
if(responseEntity.getStatusCode() == HttpStatus.OK){
System.out.println(responseEntity.getBody());
}
}

@Test
public void test02(){
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/api/v1/org/{department}/list");
HttpEntity<String> formEntity = new HttpEntity<String>(getHttpHeaders());
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, formEntity, String.class, 2);
if(responseEntity.getStatusCode() == HttpStatus.OK){
System.out.println(responseEntity.getBody());
}
}

// Mock登录授权信息
public static HttpHeaders getHttpHeaders(){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON_UTF8));
headers.add("Cookie", "token=123244545");
return headers;
}

示例参数:

  • String url: 该方法第一个参数标识请求的url
  • Class responseType: 该参数标识该次HTTP请求的结果映射成的对象类型,
  • Object… urlVariables: 该参数用来为url中的参数赋值,支持多个值传递.

RestTemplate的交互说明

上面示例中的交互可以分为三个步骤:

  1. url和参数聚合
  2. HTTP请求交互
  3. HTTP结果映射

对应的SpringRest中的如下方法.

1
2
3
4
5
@Override
public <T> T execute(String url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor<T> responseExtractor, Object... urlVariables) throws RestClientException {
URI expanded = getUriTemplateHandler().expand(url, urlVariables);
return doExecute(expanded, method, requestCallback, responseExtractor);
}

URL和参数聚合

RestTemplate的源码中使用getUriTemplateHandler().expand(url, urlVariables)来完善完成URL中占位符参数的聚合。
示例:

1
2
3
4
5
6
7
@Test
public void url(){
String url = "http://www.baidu.com?id={id}&name={name}&num={age}";
URI expanded = restTemplate.getUriTemplateHandler().expand(url, 1, "Elon", 20);
// 输出结果: http://www.baidu.com?id=1&name=Elon&num=20
System.out.println(expanded.toString());
}

RestTemplate中HTTP交互过程

http交互规范的定义

了解该块前先看看Spring中对ClientHttpRequest和对应的工厂接口的定义

ClientHttpRequest接口的定义

ClientHttpRequest接口的定义很简单,一个钩子方法

1
2
3
public interface ClientHttpRequest extends HttpRequest, HttpOutputMessage {
ClientHttpResponse execute() throws IOException;
}

ClientHttpRequest接口默认提供了如下的扩展类

ClientHttpRequestFactory接口的定义

ClientHttpRequestFactory接口的定义如下:

1
2
3
public interface ClientHttpRequestFactory {
ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException;
}

ClientHttpRequestFactory接口提供的实现类如下:

HttpAccessor的代理实现

Spring中定义了抽象类HttpAccessor, 提供了默认的ClientHttpRequestFactory实现,
ClientHttpRequestFactory默认值为SimpleClientHttpRequestFactory().

对应的HttpAccessor实现的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public abstract class HttpAccessor {

protected final Log logger = LogFactory.getLog(getClass());
private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();

public void setRequestFactory(ClientHttpRequestFactory requestFactory) {
Assert.notNull(requestFactory, "'requestFactory' must not be null");
this.requestFactory = requestFactory;
}

public ClientHttpRequestFactory getRequestFactory() {
return this.requestFactory;
}

protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
ClientHttpRequest request = getRequestFactory().createRequest(url, method);
if (logger.isDebugEnabled()) {
logger.debug("Created " + method.name() + " request for \"" + url + "\"");
}
return request;
}
}

doExecute中的钩子使用

URL构建完成后RestTemplate调用的是一个doExecute方法,该方法对应的代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
protected <T> T doExecute(URI url, HttpMethod method, RequestCallback requestCallback,	ResponseExtractor<T> responseExtractor) throws RestClientException {
Assert.notNull(url, "'url' must not be null");
Assert.notNull(method, "'method' must not be null");
ClientHttpResponse response = null;
try {
ClientHttpRequest request = createRequest(url, method);
if (requestCallback != null) {
requestCallback.doWithRequest(request);
}
response = request.execute();
handleResponse(url, method, response);
if (responseExtractor != null) {
return responseExtractor.extractData(response);
}
else {
return null;
}
}
catch (IOException ex) {
throw new ResourceAccessException("I/O error on " + method.name() +
" request for \"" + url + "\": " + ex.getMessage(), ex);
}
finally {
if (response != null) {
response.close();
}
}
}

这里的createRequest(url, method)方法集成自抽象类HttpAccessor.这样,在构建完成后,HTTP交互过程交给定义的ClientHttpRequest的规范实现.

HTTP交互结果处理

HTTP交互接口返回通过ResponseExtractor<T>该规范来处理.
ResponseExtractor接口的定义:

1
2
3
public interface ResponseExtractor<T> {
T extractData(ClientHttpResponse response) throws IOException;
}

ResponseExtractor接口默认提供的实现:

示例中我们的接口调用的返回结果实现使用的是ResponseEntityResponseExtractor<T>

1
2
3
4
5
6
7
@Override
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... urlVariables)
throws RestClientException {
RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
return execute(url, HttpMethod.GET, requestCallback, responseExtractor, urlVariables);
}

具体的实现可以参看RestTemplate,不再做过多介绍.

RestTemplate类关系图

RestTemplate类关系图

这里RestTemplate使用的常见的Rest请求的接口都定义在RestOperations中,对应的规范定义如下:

GET 规范

1
2
3
4
5
6
7
8
9
10
11
12
13
14

// GET

<T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException;

<T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException;

<T> T getForObject(URI url, Class<T> responseType) throws RestClientException;

<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientException;

<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException;

<T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException;

HEAD 规范

1
2
3
4
5
6
7
// HEAD

HttpHeaders headForHeaders(String url, Object... uriVariables) throws RestClientException;

HttpHeaders headForHeaders(String url, Map<String, ?> uriVariables) throws RestClientException;

HttpHeaders headForHeaders(URI url) throws RestClientException;

POST 规范

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// POST

URI postForLocation(String url, Object request, Object... uriVariables) throws RestClientException;

URI postForLocation(String url, Object request, Map<String, ?> uriVariables) throws RestClientException;

URI postForLocation(URI url, Object request) throws RestClientException;

<T> T postForObject(String url, Object request, Class<T> responseType, Object... uriVariables)
throws RestClientException;

<T> T postForObject(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables)
throws RestClientException;

<T> T postForObject(URI url, Object request, Class<T> responseType) throws RestClientException;

<T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Object... uriVariables)
throws RestClientException;

<T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables)
throws RestClientException;

<T> ResponseEntity<T> postForEntity(URI url, Object request, Class<T> responseType) throws RestClientException;

PUT 规范

1
2
3
4
5
6
7
// PUT

void put(String url, Object request, Object... uriVariables) throws RestClientException;

void put(String url, Object request, Map<String, ?> uriVariables) throws RestClientException;

void put(URI url, Object request) throws RestClientException;

DELETE 规范

1
2
3
4
5
6
7
// DELETE

void delete(String url, Object... uriVariables) throws RestClientException;

void delete(String url, Map<String, ?> uriVariables) throws RestClientException;

void delete(URI url) throws RestClientException;

OPTIONS 规范

1
2
3
4
5
6
7
// OPTIONS

Set<HttpMethod> optionsForAllow(String url, Object... uriVariables) throws RestClientException;

Set<HttpMethod> optionsForAllow(String url, Map<String, ?> uriVariables) throws RestClientException;

Set<HttpMethod> optionsForAllow(URI url) throws RestClientException;

在提供通用REST(GET、POST、HEAD、PUT、DELETE、OPTIONS)规范操作的基础上还提供了exchange()和execute()相关的规范操作接口定义.

RestTemplate异步模块

AsyncRestTemplate是提供的异步操作RestTemplate的组件快.使用方式比较简单.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void test(){
AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate();
String url = "http://www.baidu.com?id={id}&name={name}&num={age}";
ListenableFuture<ResponseEntity<String>> listenableFuture = asyncRestTemplate.getForEntity(url, String.class, 1, "Elon", 20);
try {
ResponseEntity<String> responseEntity = listenableFuture.get();
if(responseEntity.getStatusCode() == HttpStatus.OK){
System.out.println(responseEntity.getBody());
}
} catch (Exception e) {
LOG.error(e.getLocalizedMessage(), e);
}
}

参考文档

官方文档